package org.marverse.scripting

import util.Checkable
import ScriptingUtil._
import serialization.{Inst, S11nInfo, ObjectInput, ObjectOutput, ClassRegistry}

sealed abstract case class UncheckedInvocationExpr(val function: UncheckedExpression, val argument: UncheckedExpression)
extends UncheckedExpression {

}

object UncheckedInvocationExpr {
  def apply(function: UncheckedExpression, argument: UncheckedExpression): UncheckedInvocationExpr =
    new UncheckedInvocationExprImpl(function, argument)
}

sealed abstract case class InvocationExpr(val function: Expression, val argument: Expression)
extends Expression {

}
 

private class UncheckedInvocationExprImpl(function: UncheckedExpression, argument: UncheckedExpression) 
extends UncheckedInvocationExpr(function, argument) {
  
  override def childUncheckedExpressions = Seq(function, argument)
  
  override def checked(implicit ctx: MutableTypedMap[TypedKey, Any]): Expression = {
    val f = function.checked
    if (FunctionType(NoType, AnyType) <:: f.expressionType)
      TypeErrorExpr(f, FunctionType(NoType, AnyType))
    else {
      val a = argument.checked
      if (f.expressionType.asInstanceOf[FunctionType].argumentType >:: a.expressionType)
        TypeErrorExpr(a, f.expressionType.asInstanceOf[FunctionType].argumentType)
      else 
        new InvocationExprImpl(f, a)
    }      
  } 

}

private class InvocationExprImpl(function: Expression, argument: Expression)
extends InvocationExpr(function, argument) with Checkable {
  
  override def check(implicit ctx: MutableTypedMap[TypedKey, Any]) {
    super.check
    assertThat(FunctionType(NoType, AnyType) >=:: function.expressionType, 
      "InvocationExpr: fun(nothing, any) >=:: function(%s).expressionType(%s)".format(
        function, function.expressionType))
    assertThat(function.expressionType.asInstanceOf[FunctionType].argumentType >=:: argument.expressionType,
      "InvocationExpr: function(%s).argumentType(%s) >=:: argument(%s).expressionType(%s)".format(
        function, function.expressionType.asInstanceOf[FunctionType].argumentType, argument, argument.expressionType))
  }
  
  override def childExpressions = Seq(function, argument)  
  override def expressionType(implicit ctx: MutableTypedMap[TypedKey, Any]) = 
    function.expressionType.asInstanceOf[FunctionType].returnType
  override def evaluate(implicit ctx: MutableTypedMap[TypedKey, Any]) =
    function.evaluate.asInstanceOf[Function](argument.evaluate)
  
}

object InvocationExprS11n_0 extends Inst[InvocationExpr] {
  def ids = Seq(2)
  def classes = Seq[Class[_]](classOf[InvocationExprImpl])
  
  @throws(classOf[java.io.IOException])
  def instantiate(in: ObjectInput, id: ClassRegistry#ID, ctx: MutableTypedMap[TypedKey, Any]): InvocationExpr = {
    val function = in.read(classOf[Expression])(ctx)
    val argument = in.read(classOf[Expression])(ctx)
    new InvocationExprImpl(function, argument)
  }
  @throws(classOf[java.io.IOException])
  def serializeInstance(that: InvocationExpr, out: ObjectOutput) {
    out.write(that.function)
    out.write(that.argument)
  }
  
}
